/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.payment.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.egzosn.pay.common.bean.*;
import com.egzosn.pay.spring.boot.core.PayServiceManager;
import com.medusa.gruul.common.core.auth.client.helper.ISecurity;
import com.medusa.gruul.common.core.config.Jackson;
import com.medusa.gruul.common.core.exception.ServiceException;
import com.medusa.gruul.common.core.handler.Handler;
import com.medusa.gruul.common.core.util.SpringUtils;
import com.medusa.gruul.order.api.constant.OrderConstant;
import com.medusa.gruul.order.api.constant.OrderQueueEnum;
import com.medusa.gruul.order.api.enums.OrderStatusEnum;
import com.medusa.gruul.order.api.enums.OrderTypeEnum;
import com.medusa.gruul.order.api.feign.RemoteOrderService;
import com.medusa.gruul.order.api.model.OrderVo;
import com.medusa.gruul.payment.api.entity.*;
import com.medusa.gruul.payment.api.enums.FeeTypeEnum;
import com.medusa.gruul.payment.api.enums.PayType;
import com.medusa.gruul.payment.api.model.dto.RefundRequestDto;
import com.medusa.gruul.payment.api.model.pay.PayParam;
import com.medusa.gruul.payment.api.model.pay.OrderPayParam;
import com.medusa.gruul.payment.api.model.pay.PayResult;
import com.medusa.gruul.payment.common.annotation.PlatformHandler;
import com.medusa.gruul.payment.common.annotation.RefundHandler;
import com.medusa.gruul.payment.common.context.DetailsIdContextHolder;
import com.medusa.gruul.payment.common.model.OrderPaymentRecord;
import com.medusa.gruul.payment.conf.PayProperty;
import com.medusa.gruul.payment.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;


/**
 * 多端支付服务
 *
 * @author 张治保
 * date 2021/12/17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MultiPayServiceImpl implements MultiPayService {

    private final PayProperty payProperty;
    private final IPaymentService paymentService;
    private final PayServiceManager payServiceManager;
    private final RemoteOrderService remoteOrderService;
    private final MultiPayOrderService multiPayOrderService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object toPay(OrderPayParam params) {
        /*
         *获取并检查订单
         */
        OrderVo order = checkAndGetOrder(params.getOrderId());
        /*
         * 渲染支付参数
         */
        PayParam payParam = new PayParam()
            .setPayType(params.getPayType())
            .setSubject("MALL-商城购物")
            .setBody(StrUtil.format("共计{}个商品", order.getProductTotalQuantity()))
            .setOrderId(String.valueOf(order.getId()))
            .setRouteKey(OrderQueueEnum.QUEUE_ORDER_PAYMENT_NOTIFY.getRouteKey())
            .setPrice(order.getPayAmount())
            .setFeeType(FeeTypeEnum.CNY)
            .setSeconds(
                OrderTypeEnum.SEC_KILL == order.getType() ? TimeUnit.MINUTES.toSeconds(30L) : TimeUnit.HOURS.toSeconds(6L)
            )
            .setAttach(
                Jackson.writeValueAsString(
                    new HashMap<String, Object>(8) {
                        {
                            put("orderId", order.getId());
                            put("number", order.getProductTotalQuantity());
                            put("price", order.getPayAmount());
                            put("totalRebate", order.getRebateAmount());
                        }
                    }
                )
            );
        /*
         * 获取支付订单信息
         */
        PayResult payResult = this.toPay(payParam);
        /*
         * 订单设置业务流水号
         */
        remoteOrderService.setOrderTransactionId(params.getOrderId(), payResult.getOutTradeNo()).successData();
        return payResult;
    }

    @Override
    public PayResult toPay(PayParam payParam) {
        Handler<PayResult> handler = SpringUtils.getBean(PlatformHandler.class, ISecurity.platform().must());
        if (handler == null){
            throw new ServiceException("当前平台不支持支付");
        }
        return handler.handle(payParam);
    }

    @Override
    public String notify(String detailsId, NoticeRequest request) {
        DetailsIdContextHolder.set(detailsId);
        log.error(request.toString());
        String payBack = payServiceManager.payBack(detailsId, request);
        DetailsIdContextHolder.remove();
        return payBack;
    }

    @Override
    public String viewJump(PayType payType, String outTradeNo) {
        Payment payment = paymentService.lambdaQuery()
            .select(Payment::getOrderId)
            .eq(Payment::getTransactionId, outTradeNo)
            .one();
        return StrUtil.format(
            payProperty.getViewTemplate(),
            ISecurity.tenantId().must(),
            payType.name(),
            outTradeNo,
            payment == null ? "" : String.valueOf(payment.getOrderId())
        );
    }



    private OrderVo checkAndGetOrder(Long orderId) {
        OrderVo order = remoteOrderService.orderInfo(orderId);
        if (order == null) {
            throw new ServiceException("没有查询到需要支付的订单");
        }
        if (!OrderStatusEnum.canPay(order.getStatus())) {
            throw new ServiceException("当前状态不能支付此订单");
        }
        if (NumberUtil.isLess(order.getPayAmount(), OrderConstant.MIN_PAY_FEE)) {
            throw new ServiceException("支付金额有误");
        }
        log.info("====当前订单可以进行支付====");
        return order;
    }


}
